#include "Menu.h"
#include <iostream>

//additional includes
#include <fstream>                                    //FPW, A1
#include <algorithm>                                 //MGM: B1b B2b B3b
#include <time.h>

using namespace std;

Menu::Menu()
{
}

void Menu::display_main_menu() const 
{
   cout << "\n\nHere is the MAIN MENU \n";
   /* The following code has been written by Eric Heisler, solving problem A3 */
   if(categories.size()>0 && menu_items.size()>0) {
      string menu[categories.size()][menu_items.size()+1];
      for(int i = 0; i < categories.size(); i++) {
         menu[i][0] = categories[i].display();
         int col = 1;
         for(int j = 0; j < menu_items.size(); j++) {
            if(menu_items[j].get_cat_id() == categories[i].get_cat_id()) {
               menu[i][col++] = menu_items[j].display();
            }
         }
      }
      int len = 19;
      for(int i = 0; i < menu_items.size(); i++) {
         for(int j = 0; j < categories.size(); j++) {
            cout << menu[j][i];
            for(int k = 0; k < len - menu[j][i].size(); k++) cout << " ";
            cout << "|";
         }
         cout << "\n";
         if(i == 0) {
            for(int r = 0; r < 4*len+4; r++) {
               cout << "-";
            }
            cout << "\n";
         }
      }
   }
   else cout << "Menu hasn't been read yet. Read in the menu first.\n\n";
   /* End of code written by EMH */
}
void Menu::display_info() const
{
   /* The following code has been written by Eric Heisler, solving problem A3 */
   cout << "\nGroup Project\nProject 1\n\n"
      << "Fransiska Putri Wina Hadiwidjina\n"
      << "Muhammed Ghufron Mahfudhi\n"
      << "Eric Matthew Heisler\n"
      << "\n\nGEF Restaurant\n\n";
   /* End of code written by EMH */
}

void Menu::read()
{           
   /* The following code is written by Fransiska Putri Wina, and solves the problem A.1 */

   ifstream fileinput;                        

   int ingredient_id;                        
   int recipe_id;                           
   float amt;                           
   string units;                          
   string name;                           
   string chef_name;                       
   string word;                           
   string sentence;                        
   int ning; //number of ingredients                  
   int nrec; //number of recipe & instruction          
   int i=1; //iterator                        

   /* Start: MGM, A2 */
   string catmenuFilename = "data/catmenu.dat";
   string ordersFilename = "data/orders.dat";
   string recipesFilename = "data/recipes.dat";
   /* End: MGM, A2 */

                                 
   //Read and Store Recipe Data
   fileinput.open(recipesFilename.c_str());                        //MGM, A2
   if(!fileinput.is_open()) { // file couldn't be opened             
      cerr << "Error: file could not be opened" << endl;               
   }                                                       
   else {                                                   
      //if(category=="ingredients") {
      fileinput >> ning;                                       
      //read and store the ingredients                          
      while (i <= ning) {                                       
         fileinput >> ingredient_id;                                    
         fileinput >> recipe_id;                                 
         fileinput >> amt;                                    
         fileinput >> units;                                        
         fileinput >> name;                                    
         Ingredient ing (ingredient_id, recipe_id, amt, units, name);   
         Menu::ingredients.push_back(ing);                        
         //ingredients[i-1].displaym();                           
         i++;                                             
      }                                                   
      fileinput >> nrec;                                    
      //cout << nrec << endl;                               
      i = 1;                                                
      while (i <= nrec) {                                    
         fileinput >> recipe_id;                             
         fileinput >> chef_name;                             
         fileinput >> word;                                  
         sentence = "";                                      
         while (word != "#") {                               
            sentence = sentence + " " + word;                
            fileinput >> word;                               
         }                                                
         Instructions ins (sentence);                        
         Recipe rec (recipe_id, chef_name, ins);                 
         Menu::recipes.push_back(rec);                           
         //recipes[i-1].displaym();                              
         //cout << endl;                                       
         i++;                                             
      }                                                   
   }
   fileinput.close();                                          
   /* end of code by FPW, A.1 */

   //Read and Store Category and Menu Data
   fileinput.open(catmenuFilename.c_str());
   if(!fileinput.is_open()) { // file couldn't be opened                                     
      cerr << "Error: file could not be opened" << endl;         
   }                               
   else {   
      /* The following code is written by Eric Heisler, and solves the problem A3 */
      if(Menu::menu_items.size()==0 && Menu::categories.size()==0) {
         int type;
         fileinput >> type;   
         for(int i = 0; i < type; i++) {
            int cat_id;
            string cat_name;
            fileinput >> cat_id >> cat_name;
            Category cat (cat_id, cat_name);
            Menu::categories.push_back(cat);
         }
            
         int num_menu_items;
         fileinput >> num_menu_items;
         for(int i = 0; i < num_menu_items; i++) {
            int menu_item_id;
            int cat_id;
            int recipe_id;
            string menu_item_name;
            double price;
            string descr_string;         
      
            fileinput >> menu_item_id >> cat_id >> recipe_id >> menu_item_name >> price;
               
            string next = "";
            while(next!="#") {
               fileinput >> next;
               descr_string += " " + next;
            }
            Description descr (descr_string);
               
            Menu_Item menu_item (menu_item_id, cat_id, recipe_id, menu_item_name, price, descr);
            Menu::menu_items.push_back(menu_item);
         }
      }
   }
      /* End of code written by EMH */
   fileinput.close();                        //FPW, A1

   /* Start: MGM, A2 */
   //Read and Store Order and Order_Item Data
   fileinput.open(ordersFilename.c_str());
   if(!fileinput.is_open()) 
   { 
      // file couldn't be opened
      cerr << "Error: file could not be opened" << endl;         
   }                               
   else
   {
      int numOrder, orderID, serverID ,tableID, y, m, d, h, min, numOrderItem, ordID, MenuID, prodQty;
      char seatID;
      
      //read file (Order)
      fileinput >> numOrder;
      
      for (int i = 0; i < numOrder; i++)
      {
         fileinput >> orderID >> serverID >> tableID >> y >> m >> d >> h >> min;
         
         Order temp(orderID, serverID, tableID, Date(y, m, d), Time(h, min));
         orders.push_back(temp);
      }
      
      //read file (Order Item)
      fileinput >> numOrderItem;
      
      for (int i = 0; i < numOrderItem; i++)
      {
         fileinput >> seatID >> ordID >> MenuID >> prodQty;
         
         Order_Item temp1(seatID, ordID, MenuID, prodQty);
         order_items.push_back(temp1);
      }
      cout << "\nRecipe, Ingredient, Order, Order Item, Category, and Menu Data have been stored succesfully \n\n";

   }
   fileinput.close();
	
	sort(recipes.begin(), recipes.end());
	sort(ingredients.begin(), ingredients.end());
	sort(orders.begin(), orders.end());
	sort(menu_items.begin(), menu_items.end());
	sort(categories.begin(), categories.end());
   
   /* End: MGM, A2 */
   
} 


void Menu::show() const 
{
    cout << "\nShow queries \n";

   /* FPW B.1 a, MGM B.1 b, EMH B.1 c: START */
   int print_menu;
    Menu_Show_Queries sq;
   
   cout << "\nWhat would you want to be printed  (1, 2, 3, 4, 5)\n1. Print a menu item recipe\n2. Print all menu items sorted by Chef\n3. print all menu items in a given category sorted by price\n";
   cout << "4. Print all order IDs and tab price sorted by date\n";
   cout << "5. Print all menu item in a given order by price\n>> ";
   cin >> print_menu;

   if(print_menu == 1)
   {
      if(menu_items.size() <= 0 && recipes.size() <= 0 && ingredients.size() <= 0)
      {
         cout << "Menu items, recipes, and ingredients have not been read and stored yet.\n\n";
      }
      else
      {
         sq.B1a(menu_items,recipes,ingredients);
      }
   }
   else if(print_menu == 2)
   {
      /* print all menu items sorted by chef (MGM B.1 b: START) */
      
      if(menu_items.size() <= 0 && recipes.size() <= 0)
      {
         cout << "Menu items and recipes have not been read and stored yet.\n\n";
      }
      else
      {
         sq.B1b(menu_items, recipes);
     }
     /* print all menu items sorted by chef (MGM B.1 b: END) */
   }
   else if(print_menu == 3)
   {
      if(menu_items.size() <= 0 && categories.size() <= 0)
      {
         cout << "Menu items and categories have not been read and stored yet.\n\n";
      }
      else
      {
          sq.B1c(menu_items,categories);
      }
   }
  else if (print_menu == 4) 
   {
      if(menu_items.size() <= 0 && categories.size() <= 0)
      {
         cout << "Menu items and categories have not been read and stored yet.\n\n";
      }
      else
      {
         sq.C1a(orders, order_items, menu_items);
      }
   }
   else if (print_menu == 5)
   {
      if(menu_items.size() <= 0 && categories.size() <= 0)
         {
            cout << "Menu items and categories have not been read and stored yet.\n\n";
         }
         else
         {
            sq.C1b(orders, order_items, menu_items);
         }
   }
   else
   {
      cout << "\nError: Wrong choice. Please choose 1, 2, 3, 4, or 5\n\n.";
   }
      
   /* FPW B.1 a, MGM B.1 b, EMH B.1 c: END */
}

void Menu::find() const 
{
    cout << "\nFind queries \n";
   Menu_Find_Queries fq;
   /* FPW B.2 a, MGM B.2 b and C.2 c d, EMH B.2 c: START */
   int queryMenu;
   cout << "\nWhat sales would you like to find  (1, 2, 3, 4, 5)\n1. Total sales for a table\n2. Total sales for a server\n3. Total sales for a menu_item\n4. The top five selling menu items by revenue regardless of category\n5. The order with the largest tab price\n>> ";
   cin >> queryMenu;

   if(queryMenu == 1)
   {
      if(orders.size() <= 0 && order_items.size() <= 0 && menu_items.size() <= 0)
      {
         cout << "Orders, order items, and ingredients have not been read and stored yet.\n\n";
      }
      else
      {
         fq.B2a(orders, menu_items, order_items);
      }
   }
   else if(queryMenu == 2)
   {
      //Finding total sales for a server (MGM B.2 b)

      if(orders.size() <= 0 && order_items.size() <= 0 && menu_items.size() <= 0)
      {
         cout << "Orders, order items, and menu items have not been read and stored yet.\n\n";
      }
      else
      {
      fq.B2b(orders, menu_items, order_items);
      }
   }
   else if(queryMenu == 3)
   {
      //Finding Total sales for a menu_item (MGM B.2 c)
      if(order_items.size() <= 0 && menu_items.size() <= 0)
      {
         cout << "Order items and menu items have not been read and stored yet.\n\n";
      }
      else
      {
         fq.B2c(menu_items, order_items);
      }
   }
   else if(queryMenu == 4)
   {
      //Finding the top five selling menu items by revenue regardless of category (MGM C.2 c)
      if(menu_items.size() <= 0 && orders.size() <= 0)
      {
         cout << "Menu items and order items have not been read and stored yet.\n\n";
      }
      else
      {
         fq.C2c(menu_items, order_items);
      }
   }
   else if(queryMenu == 5)
   {
      //Finding the order with the largest tab price (MGM C.2 d)
      if(orders.size() <= 0 && order_items.size() <= 0 && menu_items.size() <= 0)
      {
         cout << "Order, order items, and menu items have not been read and stored yet.\n\n";
      }
      else
      {
      fq.C2d(orders, menu_items, order_items);
      }
   }
   else
   {
      cout << "\nError: Wrong choice. Please choose 1, 2, or 3\n\n.";
   }
   
   /* FPW B.2 a, MGM B.2 b and C.2 c d, EMH B.2 c: END */
}
void Menu::update()  
{
   cout << "Update queries \n";
   
   
   /* FPW B.3 a, MGM B.3 b, EMH B.3 c: START */
   int update_menu;
   cout << "\nWhat update would you like to perform  (1, 2, 3, 4)\n1. Update the order item in the existing order\n2. Update the menu item in the existing category\n3. Add new categories Soups, Salads and Sides\n";
   cout << "4. Add a new order given a server, table, date and time\n>> ";
   cin >> update_menu;

   if(update_menu == 1)
   {
      if(menu_items.size() <= 0 && orders.size() <= 0 && order_items.size() <= 0)
      {
         cout << "Menu items, orders, and order items have not been read and stored yet.\n\n";
      }
      else
      {
         /* Have been edited by MGM to solve the delete query */
         cout << "\nUpdate the order item in the existing order\n\n";
         int orderQuery;
         cout << "What update would you like to perform in the existing order  (1, 2)\n1. Add a new order item\n2. Delete an order item\n>> ";
         cin >> orderQuery;
         
         if(orderQuery == 1)
         {
            uq.B3a(menu_items, order_items, orders);
         }
         else if(orderQuery == 2)
         {
            uq.C_del_order_item (menu_items, order_items);
         }
         else
         {
            cout << "\nError: Wrong choice. Please choose 1 or 2\n\n.";
         }      
      }
   }
   else if (update_menu == 2)
   {
   /*
    Code was written by Eric M Heisler, and solves Part C's delete function
   */
      if(categories.size() <= 0 && recipes.size() <= 0)
      {
         cout << "Categories and recipes have not been read and stored yet.\n\n";
      }
      else
      {
         cout << "\nUpdate the menu item in the existing category\n\n";
         int menuQuery;
         cout << "What update would you like to perform in the existing category  (1, 2)\n1. Add a new menu item\n2. Delete a menu item\n>> ";
         cin >> menuQuery;
         
         if(menuQuery == 1)
         {
            uq.B3b_C3f(categories,recipes, ingredients, menu_items);
         }
      
         else if (menuQuery == 2)
         {
            cout << "\nDelete a menu item in the existing category\n\n";
            int index = uq.del_menu_item ( menu_items );
            if( index > -1 ) {
               menu_items.erase( menu_items.begin() + index );
               cout << "Delete successful.\n\n";
            }
         }
         else
         {
            cout << "\nInvalid choice. Please choose 1 or 2\n\n.";
         }
      }
    /* End of code written by EMH */
   }
   else if(update_menu == 3)
   {
      
      if(categories.size() <= 0)
      {
         cout << "Categories have not been read and stored yet.\n\n";
      }
      else
      {
         uq.B3c(categories);
      }
   }
   else if(update_menu == 4) {
	   if(categories.size() <= 0)
	   {
		   cout << "Categories have not been read and stored yet.\n\n";
	   }
	   else
	   {
		   uq.C3e(orders);
	   }
   }
   else
   {
      cout << "\nError: Wrong choice. Please choose 1, 2, 3, or 4\n\n.";
   }
   
   /* FPW B.3 a, MGM B.3 b, EMH B.3 c: START */
   
}
bool Menu::exit()         
//these following code were written by Fransiska Putri Wina to solve A.1
//these following code were updated by MGM to solve D.1
{                                             
   bool confirm_bool=false;                         
   char confirm;                                  
   cout << "Are you sure you want to exit  (y/n) \n> ";    
   cin >> confirm;                               
   if (confirm == 'y' || confirm == 'Y') {             
	   string catmenuFilename = "data/catmenu.dat";
	   string ordersFilename = "data/orders.dat";
	   string recipesFilename = "data/recipes.dat";
	   if(categories.size() <= 0 && menu_items.size() <= 0 && orders.size() <= 0 && order_items.size() <= 0 && recipes.size() <= 0 && ingredients.size() <= 0)
	   {
		   cout << "\nThe categories, menu items, orders, order items, recipes, and ingredients are\nempty. Are you sure to write the empty data into the data file? (y/n)\n>> ";
		   char in;
		   cin >> in;
		   if(in == 'y' || in == 'Y')
		   {
			   writeExitRecipes(catmenuFilename);
			   writeExitOrders(ordersFilename);
			   writeExitRecipes(recipesFilename);
			   cout << "\n\nThanks for coming to FEG Restaurant :D\n\n";
			   confirm_bool = true;
		   }
		   else if (in == 'n' || in == 'N')                        
		   {
			   confirm_bool = false; 			   
		   }
		   else
		   {
			   cout << "Invalid input. Exit aborted" << endl;
			   confirm_bool = false;
		   } 
	   }
	   else
	   {
		   writeExitOrders(ordersFilename);
		   writeExitRecipes(recipesFilename);
                   write_catmenu(catmenuFilename);
		   cout << "\n\nThanks for coming to FEG Restaurant :D\n\n";
		   confirm_bool = true; 
	   }
	                           
   }                                           
   else if (confirm == 'n' || confirm == 'N') {          
      confirm_bool = false;                         
   }                                           
   else {                                       
      cout << "Invalid input. Exit aborted" << endl;
	  confirm_bool = false;
   }                                          
   return confirm_bool;                            
}               
// end of code by FPW, A.1

/* Code to solve D1 problem by FPW, MGM, EMH */
//FPW D1
void Menu::writeExitRecipes(string filename)
{
        ofstream fileoutput;
        //Open and write Ingredients and Recipes Data
        fileoutput.open(filename.c_str());
        if(!fileoutput.is_open()) 
        { 
                // file couldn't be opened
                cerr << "Error: file could not be opened" << endl;         
        }                               
        else
        {
                //write ingredients
                fileoutput << ingredients.size() << "\n";
                for(int i = 0; i < ingredients.size(); i++)
                {
                        fileoutput << ingredients[i].get_ingredient_id() << "\t" << ingredients[i].get_recipe_id() << "\t" << ingredients[i].get_amount() << "\t" << ingredients[i].get_unit() << "\t" << ingredients[i].get_name() << "\n";
                }
                vector<string> updateIngredients = uq.getNewIngredients();
                cout << "\nThe updated ingredients has been successfully written to data file\n";
                for(int i = 0; i < updateIngredients.size(); i++)
                {
                        cout << updateIngredients[i] << endl;
                }

                //write recipes
                fileoutput << "\n" << recipes.size() << "\n";
                for(int i = 0; i < recipes.size(); i++)
                {
                        fileoutput << recipes[i].recipeId() << "\t" << recipes[i].chefName()  << "\t" << recipes[i].getInstr() << " #\n";
                }
                vector<string> updateRecipes = uq.getNewRecipes();
                cout << "\nThe updated recipes has been successfully written to  data file\n";
                for(int i = 0; i < updateRecipes.size(); i++)
                {
                        cout << updateRecipes[i] << endl;
                }
        }
        fileoutput.close();
}

//MGM D1
void Menu::writeExitOrders(string filename)
{
	ofstream fileoutput;
	//Open and write Order and Order_Item Data
	fileoutput.open(filename.c_str());
	if(!fileoutput.is_open()) 
	{ 
		// file couldn't be opened
		cerr << "Error: file could not be opened" << endl;         
	}                               
	else
	{
		//write orders
		fileoutput << orders.size() << "\n";
		for(int i = 0; i < orders.size(); i++)
		{
			fileoutput << orders[i].getOrderID() << "\t" << orders[i].getServerID() << "\t" << orders[i].getTableID() << "\t" << orders[i].getOrderDate().year() << "\t" << orders[i].getOrderDate().month() << "\t" << orders[i].getOrderDate().day() << "\t" << orders[i].getOrderTime().hour() << "\t" << orders[i].getOrderTime().minute() << "\n";
		}
		vector<string> updateOrder = uq.getNewOrders();
		cout << "\nThe updated order has been successfully written to data file\n";
		for(int i = 0; i < updateOrder.size(); i++)
		{
			cout << updateOrder[i] << endl;
		}

		//write order items
		fileoutput << "\n" << order_items.size() << "\n";
		for(int i = 0; i < order_items.size(); i++)
		{
			fileoutput << order_items[i].getSeatID() << "\t" << order_items[i].getOrderID() << "\t" << order_items[i].getMenuItemID() << "\t" << order_items[i].getProdQty() << "\n";
		}
		vector<string> updateOrderItem = uq.getNewOrderItems();
		cout << "\nThe updated order item has been successfully written to  data file\n";
		for(int i = 0; i < updateOrderItem.size(); i++)
		{
			cout << updateOrderItem[i] << endl;
		}
	}
	fileoutput.close();
}

//EMH D1
void Menu::write_catmenu(string filename)
{
     ofstream menu_item_file;
   menu_item_file.open(filename.c_str());
   if(!menu_item_file.is_open()) {
       cerr << "Error: File could not be opened." << endl;
   }
   else {
       menu_item_file << categories.size() << " \t" << endl;
       for(int i = 0; i < categories.size(); i++) {
          menu_item_file << categories[i].get_cat_id() << " " << categories[i].get_cat_name() << " \t" << endl;
       }
	   vector<string> updateCategory = uq.getNewCategories();
		cout << "\nThe updated category has been successfully written to data file\n";
		for(int i = 0; i < updateCategory.size(); i++)
		{
			cout << updateCategory[i] << endl;
		}
       menu_item_file << "\n" << menu_items.size() << " \t" << endl;
       for(int i = 0; i < menu_items.size(); i++) {
           menu_item_file << menu_items[i].get_menu_item_id() << " "
            << menu_items[i].get_cat_id() << " "
            << menu_items[i].recipeID() << " "
            << menu_items[i].get_menu_item_name() << " " 
            << menu_items[i].getPrice() << " "
            << menu_items[i].get_description().display() << " " << endl;
       }
	   vector<string> updateMenuItem = uq.getNewMenuItems();
       cout << "\nThe updated menu has been successfully written to data file.\n";
	   for(int i = 0; i < updateMenuItem.size(); i++)
		{
			cout << updateMenuItem[i] << endl;
		}
       menu_item_file.close();
    }
}